/**
 * 
 */
package prv.pursuivant.armory.impl;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import prv.pursuivant.armory.Cache;
import prv.pursuivant.config.ImporterDesc;
import prv.pursuivant.core.Achievement;
import prv.pursuivant.core.Toon;
import prv.pursuivant.core.ToonAchievements;
import prv.pursuivant.core.impl.ToonAchievementsImpl;

import com.google.inject.Inject;
import com.thoughtworks.xstream.XStream;

/**
 * @author Kwinto
 * 
 */
public class XStreamCache implements Cache {

	protected final ImporterDesc importerDesc;

	@Inject
	public XStreamCache(ImporterDesc importerDesc) {
		this.importerDesc = importerDesc;
	}

	public File getFileForToon(Toon toon) {
		final File cacheDir = new File(importerDesc.getCacheDir());
		final File categoryDir = cacheDir; // TODO: change to new File(cacheDir,
		// "" + categoryId);
		final File regionDir = new File(categoryDir, importerDesc.getRegion());
		final File realmDir = new File(regionDir, importerDesc.getRealm());
		final File toonFile = new File(realmDir, toon.getName() + ".xml");
		return toonFile;
	}

	/**
	 * @throws IOException
	 * @see prv.pursuivant.armory.Cache#read(prv.pursuivant.core.impl.ToonImpl)
	 */
	@Override
	public ToonAchievements read(Toon toon) throws IOException {
		File file = getFileForToon(toon);
		if (file.exists() && file.isFile() && file.canRead()) {
			long lastModified = file.lastModified() / 1000;
			long now = System.currentTimeMillis() / 1000;
			if (now - lastModified < importerDesc.getCacheTime() * 60) {
				return readEvenOld(toon);
			}
		}
		return null;
	}

	/**
	 * @throws IOException
	 * @see prv.pursuivant.armory.Cache#readEvenOld(prv.pursuivant.core.impl.ToonImpl)
	 */
	@Override
	public ToonAchievements readEvenOld(Toon toon) throws IOException {
		File file = getFileForToon(toon);
		FileReader fr = new FileReader(file);
		StringWriter sw = new StringWriter((int) file.length());
		char[] buffer = new char[1000];
		int len = fr.read(buffer);
		while (len >= 0) {
			sw.write(buffer, 0, len);
			len = fr.read(buffer);
		}
		fr.close();
		String xml = sw.toString();
		ToonAchievements fromXML = fromXML(toon, xml);
		return fromXML;
	}

	/**
	 * @throws IOException
	 * @see prv.pursuivant.armory.Cache#write(prv.pursuivant.core.impl.ToonImpl,
	 *      java.util.List)
	 */
	@Override
	public void write(Toon toon, ToonAchievements achievs) throws IOException {
		String xml = toXML(toon, achievs);
		File file = getFileForToon(toon);
		file.getParentFile().mkdirs();
		FileWriter fw = new FileWriter(file, false);
		fw.write(xml);
		fw.close();
	}

	/**
	 * 
	 * @param toon
	 * @param achievs
	 * @return
	 */
	public String toXML(Toon toon, ToonAchievements achievs) {
		XStream xstream = new XStreamCacheFactory().createXStreamForToon(toon);
		final List<Achievement> list = new ArrayList<Achievement>();
		for (Achievement achiev : achievs)
			list.add(achiev);
		String xml = xstream.toXML(list);
		return xml;
	}

	/**
	 * @param toon
	 * @param xml
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public ToonAchievements fromXML(Toon toon, String xml) {
		XStream xstream = new XStreamCacheFactory().createXStreamForToon(toon);
		Object fromXML = xstream.fromXML(xml);
		final List<Achievement> list = (List<Achievement>) fromXML;
		final Map<String, Achievement> achievs = new HashMap<String, Achievement>(
				list.size());
		for (Achievement achiev : list)
			achievs.put(achiev.getId(), achiev);
		return new ToonAchievementsImpl(achievs);
	}

}
